package server;

import common.GameState;
import common.PlayerColor;
import common.PlayerDirection;
import common.PlayerEvent;
import common.PlayerStatus;

class GameStatePlaying extends GameControllerState {

	private int deadCount = 0;
	
	@Override
	public void initializeState(GameController c) {
		super.initializeState(c);
		game.setPlayingState(GameState.Running);
		game.setMessage("start game");
		controller.setTimer(300);
		game.resetCoins( level);
		for( UpdateablePlayer p : game.getUpdateablePlayer()){
			p.SetPlayerStatus( PlayerStatus.ALIVE);
		}
	}

	@Override
	public void timerTick(int tickCount) {
		
		UpdateablePlayer[] player = game.getUpdateablePlayer();
		if (player == null || player.length != GameController.MAX_PLAYERS)
			throw new IllegalStateException("Game can't be in playing state without enough players");
		
		game.increaseColorChangeCount();
		if( game.getColorChangeCount() == level.getColorChangeOnTick()){
			rotateColors( player);
			game.resetColorChangeCount();
		}
		
		// update players
		for (int i = 0; i < player.length; i++) {
			if( player[i].GetStatus() == PlayerStatus.DEAD)
				continue;
			
			//if 2 players come to the same coint at the same time, who earns the coin?
			//->the one who joined the game first ;)
			player[i].advancePlayer(level);
			if( game.coinOnField( player[i].GetPosY(), player[i].GetPosX())){
				player[i].earnCoin();
				game.removeCoin(player[i].GetPosY(), player[i].GetPosX());
				if( game.getCoinsLeft() == 0){
					controller.setState(new GameStateFinished());
				}
			}
			
			//// after every player position change we check if we have a 
			//// player <-> player collision to don't miss collisions
			//---> when p1 moves, there is no need to check collision between 2 and 3!
			
			// check each player with each other player
			for (int j = 0; j < player.length; j++) {
					if( j==i || player[j].GetStatus()==PlayerStatus.DEAD)
						continue;
				
					UpdateablePlayer p1 = player[i];
					UpdateablePlayer p2 = player[j];
					UpdateablePlayer wonPlayer;
					UpdateablePlayer lostPlayer;
					
					if (p1.GetPosX() == p2.GetPosX() &&
						p1.GetPosY() == p2.GetPosY()) {
						
						// detected collision
						// red kills blue
						if ((p1.GetColor() == PlayerColor.Red && p2.GetColor() == PlayerColor.Blue) ||
						    (p1.GetColor() == PlayerColor.Blue && p2.GetColor() == PlayerColor.Green) ||
						    (p1.GetColor() == PlayerColor.Green && p2.GetColor() == PlayerColor.Red)) {
							
							wonPlayer = p1;
							lostPlayer = p2;
						} else {
							wonPlayer = p2;
							lostPlayer = p1;
						}
						
						wonPlayer.SetScore(wonPlayer.GetScore() + lostPlayer.GetScore());
						lostPlayer.SetScore(0);
						lostPlayer.SetPlayerStatus(PlayerStatus.DEAD);
						deadCount++;
						
						game.setMessage("player " + wonPlayer + 
								" killed player " + lostPlayer);
						
						if( deadCount >= player.length-1)
							controller.setState(new GameStateFinished());
					}
			}
		}
		
	}
	
	
	@Override
	public void playerEvent(UpdateablePlayer player, PlayerEvent event) {
		
		switch(event) {
		case PlayerMoveDown:  player.SetDirection(PlayerDirection.South); break;
		case PlayerMoveUp:    player.SetDirection(PlayerDirection.North); break;
		case PlayerMoveLeft:  player.SetDirection(PlayerDirection.West); break;
		case PlayerMoveRight: player.SetDirection(PlayerDirection.East); break;
		default: break;
		}
		
	}

//	this implementation becomes the default one
//	
//	@Override
//	public void playerDetached(UpdateablePlayer player) {
//		game.setMessage("player " + player.GetName() + " has left the game. waiting for a new player...");
//		controller.setState(new GameStateWaitingForPlayers());
//	}

	
	@Override
	public void detachState() {
		controller.stopTimer();
	}

	public void rotateColors( UpdateablePlayer[] player){
 		PlayerColor tempColor = player[0].GetColor(); 
		for( int i = 0; i < player.length-1; i++){
			player[i].SetColor( player[i+1].GetColor());
		}
		player[player.length-1].SetColor( tempColor);
	}
}